home *** CD-ROM | disk | FTP | other *** search
- /* Send and receive IP datagrams on serial lines. Compatible with SLIP
- * under Berkeley Unix.
- */
- #ifdef TRACE
- #include <stdio.h>
- #endif
- #include "machdep.h"
- #ifdef TRACE
- #include "trace.h"
- #endif
- #include "mbuf.h"
- #include "iface.h"
- #include "ax25.h"
- #include "slip.h"
- #ifdef AMIGA
- #include "amiga.h"
- #else
- #include "pc.h"
- #endif
-
- int slip_send();
- int doslip();
- int asy_output();
-
- /* Slip level control structure */
- struct slip slip[ASY_MAX];
- unsigned nasy;
-
- /* Send routine for point-to-point slip
- * This is a trivial function since there is no slip link-level header
- */
- int
- slip_send(bp,interface,gateway,precedence,delay,throughput,reliability)
- struct mbuf *bp; /* Buffer to send */
- struct interface *interface; /* Pointer to interface control block */
- int32 gateway; /* Ignored (SLIP is point-to-point) */
- char precedence;
- char delay;
- char throughput;
- char reliability;
- {
- /* Queue a frame on the slip output queue and start transmitter */
-
- if(interface == NULLIF){
- free_p(bp);
- return;
- }
- #ifdef TRACE
- if(trace & TRACE_SLIP){
- printf("%s sent:\r\n",interface->name);
- if((trace & TRACE_HDR) > 2)
- ip_dump(bp);
- if(trace & TRACE_DUMP)
- hexdump(bp);
- if(trace & TRACE_ASCII)
- asciidump(bp);
- fflush(stdout);
- }
- #endif
- slipq(interface->dev,bp);
- }
- /* Encode a packet in slip framing, put on link output queue, and kick
- * transmitter
- */
- slipq(dev,bp)
- int16 dev; /* Serial line number */
- struct mbuf *bp; /* Buffer to be sent */
- {
- register struct slip *sp;
- struct mbuf *slip_encode();
-
- if((bp = slip_encode(bp)) == NULLBUF)
- return;
-
- sp = &slip[dev];
- enqueue(&sp->sndq,bp);
- sp->sndcnt++;
- if(sp->tbp == NULLBUF)
- asy_start(dev);
- }
- /* Start output, if possible, on asynch device dev */
- static
- asy_start(dev)
- int16 dev;
- {
- register struct slip *sp;
-
- if(!stxrdy(dev))
- return; /* Transmitter not ready */
-
- sp = &slip[dev];
- if(sp->tbp != NULLBUF){
- /* transmission just completed */
- free_p(sp->tbp);
- sp->tbp = NULLBUF;
- }
- if(sp->sndq == NULLBUF)
- return; /* No work */
-
- sp->tbp = dequeue(&sp->sndq);
- sp->sndcnt--;
- asy_output(dev,sp->tbp->data,sp->tbp->cnt);
- }
- /* Encode a packet in SLIP format */
- static
- struct mbuf *
- slip_encode(bp)
- struct mbuf *bp;
- {
- struct mbuf *lbp; /* Mbuf containing line-ready packet */
- register char *cp;
- register int cnt;
- char c;
-
- /* Allocate output mbuf that's twice as long as the packet.
- * This is a worst-case guess (consider a packet full of FR_ENDs!)
- */
- lbp = alloc_mbuf(2*len_mbuf(bp) + 2);
- if(lbp == NULLBUF){
- /* No space; drop */
- free_p(bp);
- return NULLBUF;
- }
- cp = lbp->data;
- cnt = 0;
-
- /* Flush out any line garbage */
- *cp++ = FR_END;
- cnt++;
-
- /* Copy input to output, escaping special characters */
- while(pullup(&bp,&c,1) == 1){
- switch(c & 0xff){
- case FR_ESC:
- *cp++ = FR_ESC;
- *cp++ = T_FR_ESC;
- cnt += 2;
- break;
- case FR_END:
- *cp++ = FR_ESC;
- *cp++ = T_FR_END;
- cnt += 2;
- break;
- default:
- *cp++ = c;
- cnt++;
- }
- }
- *cp++ = FR_END;
- cnt++;
- lbp->cnt = cnt;
- return lbp;
- }
- /* Process incoming bytes in SLIP format
- * When a buffer is complete, return it; otherwise NULLBUF
- */
- static
- struct mbuf *
- slip_decode(dev,c)
- int dev; /* Slip unit number */
- char c; /* Incoming character */
- {
- struct mbuf *bp,*nbp;
- register struct slip *sp;
-
- sp = &slip[dev];
- switch(c & 0xff){
- case FR_END:
- if(sp->rbp != NULLBUF){
- /* Kick upstairs */
- bp = sp->rbp;
- sp->rbp = NULLBUF;
- sp->rcnt = 0;
- /* Copy into contiguous buffer, if necessary */
- if(bp->next != NULLBUF){
- nbp = copy_p(bp,len_mbuf(bp));
- free_p(bp);
- bp = nbp;
- }
- return bp;
- }
- return NULLBUF;
- case FR_ESC:
- sp->escaped = 1;
- return NULLBUF;
- }
- if(sp->escaped){
- sp->escaped = 0;
- switch(c & 0xff){
- case T_FR_ESC:
- c = FR_ESC;
- break;
- case T_FR_END:
- c = FR_END;
- break;
- default:
- sp->errors++;
- }
- }
- if(sp->rcnt == SLIP_MTU){
- /* Packet is too large, drop it and start over */
- free_p(sp->rbp);
- sp->rbp = NULLBUF;
- sp->rcnt = 0;
- return NULLBUF;
- }
- /* We reach here with a character for the buffer;
- * make sure there's space for it
- */
- if(sp->rbp == NULLBUF){
- /* Allocate first mbuf for new packet */
- if((sp->rbp1 = sp->rbp = alloc_mbuf(SLIP_ALLOC)) == NULLBUF)
- return NULLBUF; /* No memory, drop */
- sp->rcp = sp->rbp->data;
- } else if(sp->rbp1->cnt == SLIP_ALLOC){
- /* Current mbuf is full; link in another */
- if((sp->rbp1->next = alloc_mbuf(SLIP_ALLOC)) == NULLBUF){
- /* No memory, drop whole thing */
- free_p(sp->rbp);
- sp->rbp = NULLBUF;
- sp->rcnt = 0;
- return NULLBUF;
- }
- sp->rbp1 = sp->rbp1->next;
- sp->rcp = sp->rbp1->data;
- }
- /* Store the character, increment fragment and total
- * byte counts
- */
- *sp->rcp++ = c;
- sp->rbp1->cnt++;
- sp->rcnt++;
- return NULLBUF;
- }
- /* Process SLIP line I/O */
- int
- doslip(interface)
- struct interface *interface;
- {
- char c;
- struct mbuf *bp;
- int16 dev;
-
- dev = interface->dev;
- /* Process any pending input */
- while(asy_recv(dev,&c,1) != 0)
- if((bp = slip_decode(dev,c)) != NULLBUF)
- (*slip[dev].recv)(interface,bp);
-
- /* Kick the transmitter if it's idle */
- if(stxrdy(dev))
- asy_start(dev);
- }
- /* Unwrap incoming SLIP packets -- trivial operation since there's no
- * link level header
- */
- slip_recv(interface,bp)
- struct interface *interface;
- struct mbuf *bp;
- {
- #ifdef TRACE
- if(trace & TRACE_SLIP){
- printf("%s recv:\r\n",interface->name);
- if((trace & TRACE_HDR) > 2)
- ip_dump(bp);
- if(trace & TRACE_DUMP)
- hexdump(bp);
- if(trace & TRACE_ASCII)
- asciidump(bp);
- fflush(stdout);
- }
- #endif
- ip_route(bp,0);
- }
- /* Attach a serial interface to the system
- * argv[0]: hardware type, must be "asy"
- * argv[1]: I/O address, e.g., "0x3f8"
- * argv[2]: vector, e.g., "4"
- * argv[3]: mode, may be:
- * "slip" (point-to-point SLIP)
- * "ax25" (AX.25 UI frame format in SLIP for raw TNC)
- * argv[4]: interface label, e.g., "sl0"
- * argv[5]: receiver ring buffer size in bytes
- * argv[6]: maximum transmission unit, bytes
- * argv[7]: interface speed, e.g, "9600"
- */
- asy_attach(argc,argv)
- int argc;
- char *argv[];
- {
- register struct interface *if_asy;
- extern struct interface *ifaces;
- int dev;
- char *malloc(), *calloc();
- int asy_init();
- int asy_send();
- int doslip();
- int asy_stop();
- int ax_send();
- int kiss_recv();
- int kiss_output();
-
- if(nasy >= ASY_MAX){
- printf("Too many asynch controllers\r\n");
- return -1;
- }
- dev = nasy++;
-
- /* Initialize hardware-level control structure */
- asy[dev].addr = htoi(argv[1]);
- asy[dev].vec = htoi(argv[2]);
-
- /* Create interface structure and fill in details */
- if_asy = (struct interface *)calloc(1, sizeof(struct interface));
-
- if_asy->name = malloc(strlen(argv[4])+1);
- strcpy(if_asy->name,argv[4]);
- if_asy->mtu = atoi(argv[6]);
- if_asy->dev = dev;
- if_asy->recv = doslip;
- if_asy->stop = asy_stop;
-
- if(strcmp(argv[3],"slip") == 0){
- if_asy->send = slip_send;
- if_asy->output = NULLFP;
- if_asy->flags = 0;
- slip[dev].recv = slip_recv;
- }
- else if(strcmp(argv[3],"ax25") == 0){
- if_asy->send = ax_send;
- if_asy->output = kiss_output;
- if_asy->flags = IF_BROADCAST;
- if(if_asy->hwaddr == NULLCHAR)
- if_asy->hwaddr = malloc(AXALEN);
- bcopy((char *)&mycall,if_asy->hwaddr,AXALEN);
- slip[dev].recv = kiss_recv;
- }
- else {
- printf("Mode %s unknown for interface %s\r\n",
- argv[3],argv[4]);
- free((char *)if_asy);
- return -1;
- }
- if_asy->next = ifaces;
- ifaces = if_asy;
- asy_init(dev,(unsigned)atoi(argv[5]));
- asy_speed(dev,atoi(argv[7]));
- }
-